package cn.mw.cmdb.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import cn.mw.cmdb.entity.ModelGroupInfo;
import cn.mw.cmdb.entity.ModelInfo;
import cn.mw.cmdb.enums.OperatorTypeDescEnum;
import cn.mw.cmdb.exception.DelGroupChildExistException;
import cn.mw.cmdb.exception.DelGroupModelExistException;
import cn.mw.cmdb.exception.ModelGroupExistException;
import cn.mw.cmdb.mongoMapper.ModelGroupInfoMapper;
import cn.mw.cmdb.mongoMapper.ModelInfoMapper;
import cn.mw.cmdb.param.GroupSearchParam;
import cn.mw.cmdb.param.ModelSearchParam;
import cn.mw.cmdb.processor.MonitorGroupInfo;
import cn.mw.cmdb.processor.MonitorGroupInfoList;
import cn.mw.cmdb.processor.MonitorParamContext;
import cn.mw.cmdb.processor.MonitorProcessor;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.components.mongodb.entity.SearchParam;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.log.client.LogClientSimple;
import cn.mw.log.enums.BusinessLogType;
import cn.mw.log.enums.LogLevel;
import cn.mw.main.api.common.ZabbixDubboService;
import cn.mw.microMonitorCommon.api.common.MwTPServerService;
import cn.mw.microMonitorCommon.constant.Constants;
import cn.mw.microMonitorCommon.entity.common.MwTPServerTable;
import cn.mw.microMonitorCommon.enums.ServerTypeEnum;
import cn.mw.microMonitorCommon.security.utils.SecurityUtils;
import cn.mw.microMonitorCommon.util.DateUtils;
import cn.mw.microMonitorCommon.util.SpringUtils;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.mw.cmdb.enums.PageDescEnum.ModelGroup;
import static cn.mw.cmdb.util.ValConvertUtil.intValueConvert;
@Slf4j
public class ModelGroupServiceImpl extends ModelBaseServiceImpl<ModelGroupInfo, Object> {

    public static final String ID = "modelGroupService";
    public static final String groupPrefix = "Other";

    private ModelGroupInfoMapper modelGroupInfoMapper;

    private ModelInfoMapper modelInfoMapper;

    private MwTPServerService mwTPServerService;

    private CmdbServiceManage cmdbServiceManage;
    private LogClientSimple logClientSimple;

    private ZabbixDubboService zabbixDubboService;

    public ModelGroupServiceImpl(ModelGroupInfoMapper modelGroupInfoMapper, ModelInfoMapper modelInfoMapper,
                                 MwTPServerService mwTPServerService, CmdbServiceManage cmdbServiceManage, ZabbixDubboService zabbixDubboService) {
        this.modelGroupInfoMapper = modelGroupInfoMapper;
        this.modelInfoMapper = modelInfoMapper;
        this.mwTPServerService = mwTPServerService;
        this.cmdbServiceManage = cmdbServiceManage;
        this.zabbixDubboService = zabbixDubboService;
    }

    public ModelGroupServiceImpl() {
        this.logClientSimple = SpringUtil.getBean(LogClientSimple.class);
    }

    @Override
    public ModelGroupInfo genObject() {
        return new ModelGroupInfo();
    }

    @Override
    Object doAdd(ModelGroupInfo param) throws Exception {
        checkGroup(param);
        CMDBTool.initCreateInfo(param);
        return modelGroupInfoMapper.insert(param);
    }

    @Override
    boolean doUpdate(ModelGroupInfo param) throws Exception {
        checkGroup(param);
        Query query = new Query(CriteriaWrapper.where(ModelGroupInfo::getId).is(param.getId()));
        CMDBTool.initUpdateInfo(param);
        Update update = CMDBTool.genMongoUpdate(param, null, null);
        CMDBTool.updateFirst(modelGroupInfoMapper, query, update);
        return true;
    }

    @Override
    boolean doRemove(ModelGroupInfo param) throws Exception {
        //确认分组下是否关联了模型信息
        Query query = new Query(CriteriaWrapper.where(ModelInfo::getGroupId).in(param.getId()));
        List<ModelInfo> modelInfos = CMDBTool.logicSelectList(modelInfoMapper, ModelInfo.class, query);
        if (null != modelInfos && modelInfos.size() > 0) {
            throw new DelGroupModelExistException();
        }

        //确认是否存在子分组
        query = new Query(CriteriaWrapper.where(ModelGroupInfo::getPath).in(param.getId()));
        query.addCriteria(CriteriaWrapper.where(ModelGroupInfo::getDelFlag).is(false));
        List<ModelGroupInfo> list = modelGroupInfoMapper.find(query);
        if (null != list && list.size() > 0) {
            throw new DelGroupChildExistException();
        }

        CMDBTool.remove(modelGroupInfoMapper, param.getId(), ModelGroupInfo.class, true);
        return true;
    }

    @Override
    Object doBatchAdd(Object params) {
        return false;
    }

    @Override
    boolean doBatchUpdate(Object params) {
        return false;
    }

    @Override
    public ModelGroupInfo doSelectById(Object id) {
        ModelGroupInfo modelGroupInfo = (ModelGroupInfo) id;
        return modelGroupInfoMapper.findById(modelGroupInfo.getId());
    }

    public List<ModelGroupInfo> doSelectByIds(List<String> idList) throws Exception {
        Query query = genQueryByIds(idList);
        query.addCriteria(CriteriaWrapper.where(ModelGroupInfo::getDelFlag).is(false));
        return modelGroupInfoMapper.find(query);
    }


    @Override
    public List<ModelGroupInfo> doSelectList(Object param) throws Exception {
        SearchParam searchParam = (SearchParam) param;
        //获取参数值对对应属性类型,并生成查询条件
        Criteria criteria = genCriteria(searchParam, true);
        Query query = new Query();
        if (criteria != null) {
            query = new Query(criteria);
        }
        query.addCriteria(CriteriaWrapper.where(ModelGroupInfo::getDelFlag).is(false));
        List<ModelGroupInfo> ret = CMDBTool.selectList(ModelGroupInfo.class, modelGroupInfoMapper, query, searchParam);
        return ret;
    }

    /**
     * 获取父模型分组
     *
     * @param param
     * @return
     * @throws Exception
     */
    public List<ModelGroupInfo> getParentModelGroupList(Object param) throws Exception {
        GroupSearchParam searchParam = (GroupSearchParam) param;
        searchParam.convert();
        Criteria criteria = genCriteria(searchParam);
        List<ModelGroupInfo> ret = CMDBTool.selectAuthorizedList(ModelGroupInfo.class, modelGroupInfoMapper, criteria, searchParam);
        return ret;
    }


    /**
     * 获取可显示的模型分组
     *
     * @param param
     * @return
     * @throws Exception
     */
    public List<ModelGroupInfo> getShowModelGroupList(Object param) throws Exception {
        GroupSearchParam searchParam = (GroupSearchParam) param;
        //获取可显示的模型分组
//        searchParam.addSubCondition(CMDBTool.getFieldName(ModelGroupInfo::getVisible)
//                , new SubCondition(CriteriaOpsType.is.name(), true));
        searchParam.convert();
        Criteria criteria = genCriteria(searchParam);
        if (criteria == null) {
            criteria = new Criteria();
        }
        criteria.and(CMDBTool.getFieldName(ModelGroupInfo::getVisible)).is(true);
        List<ModelGroupInfo> ret = CMDBTool.selectAuthorizedList(ModelGroupInfo.class, modelGroupInfoMapper, criteria, searchParam);
        return ret;
    }

    public List<ModelGroupInfo> doSelectAll() throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelGroupInfo::getDelFlag).is(false));
        return modelGroupInfoMapper.find(query);
    }

    @Override
    boolean doBatchRemove(Object params) throws Exception {
        return false;
    }

    public List getTreeList(SearchParam searchParam) throws Exception {

        List<ModelGroupInfo> list = doSelectList(searchParam);

        List ret = new ArrayList();
        //找到父id
        Set<String> parentIds = new HashSet<>();
        for (ModelGroupInfo modelGroupInfo : list) {
            if (null != modelGroupInfo.getPath()) {
                parentIds.addAll(modelGroupInfo.getPath());
            }
        }

        for (ModelGroupInfo modelGroupInfo : list) {
            parentIds.remove(modelGroupInfo.getId());
        }

        if (parentIds.size() > 0) {
            Query query = genQueryByIds(new ArrayList(parentIds));
            query.addCriteria(CriteriaWrapper.where(ModelGroupInfo::getDelFlag).is(false));
            if (null != query) {
                List<ModelGroupInfo> parents = modelGroupInfoMapper.find(query);
                list.addAll(parents);
            }

        }
        ret.addAll(list);
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelSearchParam modelSearchParam = new ModelSearchParam();
        List<ModelInfo> modelInfos = modelService.selectList(modelSearchParam);
        Map<String, Long> collect = modelInfos.stream().filter(s -> CollectionUtils.isNotEmpty(s.getGroupPath())).flatMap(bean -> bean.getGroupPath().stream()).collect(Collectors.groupingBy(s -> s, Collectors.counting()));
        for (ModelGroupInfo groupInfo : list) {
            String id = groupInfo.getId();
            if (collect != null && collect.containsKey(id)) {
                groupInfo.setCount(intValueConvert(collect.get(id)));
            }
        }
        return ret;
    }

    public void syncGroupInfoFromMoniterServer() throws Exception {
        List<MwTPServerTable> mwTPServerTables = mwTPServerService.getAllMwTpServer(ServerTypeEnum.Zabbix.getCode(), false);

        //可能存在不通类型的监控服务器,如zabbix, prometheus
        List<MwTPServerTable> servers = new ArrayList<>();
        for (MwTPServerTable mwTPServerTable : mwTPServerTables) {
            if (!mwTPServerTable.getDeleteFlag()) {
                servers.add(mwTPServerTable);
            }
        }
        String baseGroupId = SpringUtils.getPropertiesValue("base.groupId");
        if (servers.size() > 0) {
            Query query = new Query(CriteriaWrapper.where(ModelGroupInfo::getDelFlag).is(false));
            List<ModelGroupInfo> modelGroupInfos = modelGroupInfoMapper.find(query);
            for (ModelGroupInfo modelGroupInfo : modelGroupInfos) {
                modelGroupInfo.setMonitorGroupInfos(new ArrayList<>());
                if(modelGroupInfo.getPath()==null || !modelGroupInfo.getPath().contains(baseGroupId)){
                    String name = modelGroupInfo.getName();
                    modelGroupInfo.setName(groupPrefix + name);
                }
            }
            for (MwTPServerTable server : servers) {
                MonitorProcessor processor = MonitorProcessor.build(server, null);
                MonitorParamContext context = MonitorParamContext.build();
                context.setZabbixDubboService(zabbixDubboService);
                MonitorGroupInfoList result = processor.getGroupInfo(context);
                //未匹配的分组名称
                Set<String> nameList = new HashSet<>();
                if (null != result && null != result.getGroupInfoList()) {
                    Map<String, MonitorGroupInfo> groupNameIdMap = result.getGroupInfoList().stream()
                            .collect(Collectors.toMap(MonitorGroupInfo::getName, Function.identity()));
                    for (ModelGroupInfo modelGroupInfo : modelGroupInfos) {
                        MonitorGroupInfo monitorGroupInfo = groupNameIdMap.get(modelGroupInfo.getName());
                        if (null != monitorGroupInfo) {//匹配的分组设置groupId
                            monitorGroupInfo.setServerId(server.getId());
                            modelGroupInfo.getMonitorGroupInfos().add(monitorGroupInfo);
                        } else {
                            if (CollectionUtils.isNotEmpty(modelGroupInfo.getPath())) {
                                nameList.add(modelGroupInfo.getName());
                            }
                        }
                    }
                }
                //没有匹配的数据，创建zabbix分组
                context.setGroupNameList(new ArrayList<>(nameList));
                if (CollectionUtils.isNotEmpty(nameList)) {
                    log.info("into createGroupInfo param::"+nameList);
                    MonitorGroupInfoList groupInfo = processor.createGroupInfo(context);
                    if (null != groupInfo && null != groupInfo.getGroupInfoList()) {
                        Map<String, MonitorGroupInfo> groupNameIdMap = groupInfo.getGroupInfoList().stream()
                                .collect(Collectors.toMap(MonitorGroupInfo::getName, Function.identity()));
                        for (ModelGroupInfo modelGroupInfo : modelGroupInfos) {
                            MonitorGroupInfo monitorGroupInfo = groupNameIdMap.get(modelGroupInfo.getName());
                            if (null != monitorGroupInfo) {
                                monitorGroupInfo.setServerId(server.getId());
                                modelGroupInfo.getMonitorGroupInfos().add(monitorGroupInfo);
                            }
                        }
                    }
                }
            }
            //获取所有分组信息
            batchUpdateTemplate(modelGroupInfoMapper, modelGroupInfos, ModelGroupInfo.class, context -> {
                try {
                    Query querys = new Query(CriteriaWrapper.where(ModelGroupInfo::getId).is(context.getData().getId()));
                    Update update = new Update();
                    // 更新数据
                    update.set(CMDBTool.getFieldName(ModelGroupInfo::getMonitorGroupInfos), context.getData().getMonitorGroupInfos());
                    context.setQuery(querys);
                    context.setUpdate(update);
                } catch (Exception e) {

                }
            });
        }
    }


    private void checkGroup(ModelGroupInfo param) throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelGroupInfo::getName).is(param.getName()));
        query.addCriteria(CriteriaWrapper.where(ModelGroupInfo::getDelFlag).is(false));
        query.addCriteria(CriteriaWrapper.where(ModelGroupInfo::getPath).is(param.getPath()));
        if(!Strings.isNullOrEmpty(param.getId())){
            query.addCriteria(CriteriaWrapper.where(ModelGroupInfo::getId).ne(param.getId()));
        }
        long count = modelGroupInfoMapper.count(query);
        if(count > 0){
            throw new ModelGroupExistException("mw-group-exist-err");
        }
    }


    /**
     * 新增异常日志记录
     *
     * @param param
     */
    public void addRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelGroupInfo) {
            ModelGroupInfo info = (ModelGroupInfo) param;
            name = info.getName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.add.getCname() + ModelGroup.getDesc(),
                        OperatorTypeDescEnum.add.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 修改异常日志记录
     *
     * @param param
     */
    public void updateRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelGroupInfo) {
            ModelGroupInfo info = (ModelGroupInfo) param;
            name = info.getName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.update.getCname() + ModelGroup.getDesc(),
                        OperatorTypeDescEnum.update.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 删除异常日志记录
     *
     * @param param
     */
    private void removeRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelGroupInfo) {
            ModelGroupInfo info = (ModelGroupInfo) param;
            name = info.getName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.remove.getCname() + ModelGroup.getDesc(),
                        OperatorTypeDescEnum.remove.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 批量新增异常日志记录
     *
     * @param param
     */
    private void batchAddRecordMethod(Object param) {

    }

    /**
     * 批量修改异常日志记录
     *
     * @param param
     */
    private void batchUpdateRecordMethod(Object param) {

    }

    /**
     * 批量删除异常日志记录
     *
     * @param param
     */
    private void batchRemoveRecordMethod(Object param) {

    }
}
